/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mygame.Scene;

import java.util.ArrayList;

import mygame.Manager;
import mygame.TerrainGenerator.HeightMap;
import mygame.TerrainGenerator.MeshGenerator;

import com.jme3.asset.AssetManager;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Plane;
import com.jme3.math.Quaternion;
import com.jme3.math.Triangle;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Quad;
import com.jme3.terrain.geomipmap.TerrainPatch;
import com.jme3.util.SkyFactory;
import com.jme3.water.SimpleWaterProcessor;

/**
 *
 * @author Tobi
 */
public class SceneManager {

    private Node root;
    private Node collisionScene;
    private Node Scene;
    private Node ground;
    private AssetManager asm;
    private ViewPort vp;
    private ArrayList<RigidBodyControl> controls;
    private ArrayList<PlacementTriangle> triangles;

    public SceneManager(Node root, AssetManager assetManager, ViewPort vp) {
        collisionScene = new Node("CollisionScene");
        Scene = new Node("Scene");
        this.root = root;
        root.attachChild(Scene);

        Scene.attachChild(collisionScene);
        this.asm = assetManager;
        this.vp = vp;
        controls = new ArrayList<RigidBodyControl>();
    }

    public void init() {
    	ground = new Node("ground");
    	Scene.attachChild(ground);
    	
//    	Box b = new Box(Vector3f.ZERO, 10, 0.4f, 10);
//        Geometry geom = new Geometry("Box",b);
//        Material m = new Material(asm, "Common/MatDefs/Misc/Unshaded.j3md");
//        m.setColor("Color", ColorRGBA.Red);
//        geom.setMaterial(m);
//        geom.setLocalTranslation(0, -5, 0);
//        ground.attachChild(geom);
//        ground.setShadowMode(ShadowMode.CastAndReceive);
//        //attachScene();
//        Scene.attachChild(SkyFactory.createSky(asm, "Textures/Sky/sky2.jpg", true));
//        //addWater();
//        makeCollidable();
    }
    
    private void attachScene() {
    	
        
        //Load terrain from File
    	HeightMap hM = new HeightMap("E:\\3D Models\\h.bmp");
		Geometry terrain = MeshGenerator.generateTerrainFromHeightMap(hM, 2, 0.1f);
    	Material gMat = asm.loadMaterial("Materials/Ground.j3m");
    	gMat.setReceivesShadows(true);
    	terrain.setMaterial(gMat);
        //Spatial terrain = asm.loadModel("Models/Terrain/Isle.j3o");
        terrain.setLocalScale(2f,1f,2f);
		
        ground.setLocalTranslation(0,-20,0);
        ground.attachChild(terrain);

        //int vis_ground = 1000;
        //Quad q = new Quad(vis_ground, vis_ground);

        //Geometry g = new Geometry("Grounding", q);
        //g.setMaterial(asm.loadMaterial("Materials/Ground.j3m"));
        //g.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
        //g.setLocalTranslation(-vis_ground / 2, -12, vis_ground / 2);
        //Scene.attachChild(g);

    }

    private void makeCollidable() {
        addToPhysix(ground, 0);
//        for (int x = 0; x < collisionScene.getChildren().size(); x++) {
//            addToPhysix(collisionScene.getChild(x), x);
//        }
    }

    private void addToPhysix(Spatial s, int x) {
        CollisionShape shape = CollisionShapeFactory.createMeshShape(s);
        controls.add(new RigidBodyControl(shape, 0f));
        s.addControl(controls.get(x));
        Manager.GetInstance().getPhysix().getPhysicsSpace().add(controls.get(x));
    }

    private Mesh getMeshFromNode(Node node) {
        while (!node.getChild(0).getClass().equals(Geometry.class) && !node.getChild(0).getClass().equals(TerrainPatch.class)) {
            node = (Node) node.getChild(0);
        }
        Mesh m = new Mesh();
        if (node.getChild(1).getClass().equals(Geometry.class)) {
            m = ((Geometry) node.getChild(1)).getMesh();
        } else if (node.getChild(1).getClass().equals(TerrainPatch.class)) {
            m = ((TerrainPatch) node.getChild(1)).getMesh();
        }
        return m;
    }

    public ArrayList<PlacementTriangle> getGroundTriangles() {
        if (this.triangles != null) {
            return this.triangles;
        } else {
            Node node = ground;
            while (!node.getChild(0).getClass().equals(Geometry.class) && !node.getChild(0).getClass().equals(TerrainPatch.class)) {
                node = (Node) node.getChild(0);
            }
            ArrayList<PlacementTriangle> tl = new ArrayList<PlacementTriangle>();
            if (node.getChild(1).getClass().equals(TerrainPatch.class)) {
                for (int x = 0; x < node.getChildren().size(); x++) {
                    findTrianglesLookingUp((Geometry) node.getChild(x), tl, ground.getLocalTranslation());
                }
            }
            this.triangles = tl;
            return tl;
        }
    }

    private void findTrianglesLookingUp(Geometry g, ArrayList<PlacementTriangle> tl, Vector3f translation) {

        Mesh m = g.getMesh();

        for (int x = 0; x < m.getTriangleCount(); x++) {
            Triangle t = new Triangle();
            m.getTriangle(x, t);

            //onley use triangles that are pointing upwards and that are not deeper than XY
            if (t.getNormal().y > 0.8 && t.getCenter().y > 1) {
                //.mult(ground.getLocalScale())
                t.set1(t.get1().add(g.getLocalTranslation().add(translation)));
                t.set2(t.get2().add(g.getLocalTranslation().add(translation)));
                t.set3(t.get3().add(g.getLocalTranslation().add(translation)));
                t.calculateCenter();
                t.calculateNormal();
                
                tl.add(new PlacementTriangle(t.getCenter(), t.getNormal()));
            }
        }
    }

    public Node getGround() {
        return this.ground;
    }

    private void addWater() {
        // we create a water processor
        SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(asm);
        waterProcessor.setReflectionScene(Scene);
        // we set the water plane
        Vector3f waterLocation = new Vector3f(0, 1, 0);
        waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
        vp.addProcessor(waterProcessor);
        // we set wave properties
        waterProcessor.setWaterDepth(0.1f);         // transparency of water
        waterProcessor.setDistortionScale(0.05f); // strength of waves
        waterProcessor.setWaveSpeed(0.05f);       // speed of waves
        // we define the wave size by setting the size of the texture coordinates
        Quad quad = new Quad(1000, 1000);
        quad.scaleTextureCoordinates(new Vector2f(6f, 6f));
        // we create the water geometry from the quad
        Geometry water = new Geometry("water", quad);
        water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
        water.setLocalTranslation(-500, 1, 500);
        water.setShadowMode(ShadowMode.Receive);
        water.setMaterial(waterProcessor.getMaterial());
        root.attachChild(water);
    }
//    public String saveTriangleList() {
//        String s = "";
//        for (int x = 0; x < this.triangles.size(); x++) {
//            s += GlobalVars.DELIMITER_OBJECTS;
//            s += this.triangles.get(x).getClass().toString() + x;
//            s += this.triangles.get(x).save();
//        }
//        return s;
//    }
//
//    public ArrayList<PlacementTriangle> loadTriangleList(String l) {
//        ArrayList<PlacementTriangle> tl = new ArrayList<PlacementTriangle>();
//        String[] os = l.split(GlobalVars.DELIMITER_OBJECTS);
//
//        for (int x = 0; x < os.length; x++) {
//            tl.add(PlacementTriangle.load(os[x]));
//        }
//        return tl;
//    }
}
